import sys
from PyQt5 import QtWidgets, uic, QtGui

import colors
from core import CpuTask, FIFOScheduler, PriorityScheduler, RoundRobinScheduler
from colors import random_color
from QCpuTaskList import QCpuTaskList, QCpuTaskItem

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi('main.ui', self)

        # 控件
        self.groupBox: QtWidgets.QGroupBox
        self.sa_preview: QtWidgets.QScrollArea
        self.btn_task_add: QtWidgets.QPushButton
        self.btn_task_save: QtWidgets.QPushButton
        self.btn_task_delete: QtWidgets.QPushButton
        self.edt_tick_duration: QtWidgets.QLineEdit
        self.spn_quantum_ticks: QtWidgets.QSpinBox
        self.spn_task_priority: QtWidgets.QSpinBox
        self.spn_task_ticks: QtWidgets.QSpinBox
        self.lst_tasks: QtWidgets.QListView
        self.rdo_scheduler_fifo: QtWidgets.QRadioButton
        self.rdo_scheduler_priority: QtWidgets.QRadioButton
        self.rdo_scheduler_robin: QtWidgets.QRadioButton
        self.btn_start_stop: QtWidgets.QPushButton

        # 连接信号和槽
        self.btn_start_stop.clicked.connect(self.start_stop)
        self.btn_task_add.clicked.connect(self.add_task)
        self.btn_task_save.clicked.connect(self.save_task)
        self.btn_task_delete.clicked.connect(self.delete_task)
        
        # 其他
        self.tasks: list[CpuTask] = [
            CpuTask(number=1, priority=1, cost_ticks=6),
            CpuTask(number=2, priority=2, cost_ticks=4),
            CpuTask(number=3, priority=3, cost_ticks=1),
        ]
        self.started = False
        self.cpu = QCpuTaskList([], 1)
        self.scheduler: FIFOScheduler = FIFOScheduler()
        self.color_map: dict[int, str] = {}
        
        self.sa_preview.setWidget(self.cpu)
        self.sa_preview.setWidgetResizable(True)
        self.update_task_list()

    def start_stop(self):
        if self.started:
            self.btn_start_stop.setText("开始")
            self.started = False
            self.stop()
        else:
            self.btn_start_stop.setText("停止")
            self.started = True
            self.start()

    def start(self):
        tick_duration = float(self.edt_tick_duration.text())
        quantum_ticks = self.spn_quantum_ticks.value()
        if self.rdo_scheduler_fifo.isChecked():
            self.scheduler = FIFOScheduler(self.tasks)
        elif self.rdo_scheduler_priority.isChecked():
            self.scheduler = PriorityScheduler(self.tasks)
        elif self.rdo_scheduler_robin.isChecked():
            self.scheduler = RoundRobinScheduler(self.tasks, quantum_tick=quantum_ticks)
        else:
            QtWidgets.QMessageBox.warning(self, "错误", "请选择调度算法")
            return
        self.cpu.clear()
        self.scheduler.tick_duration = tick_duration
        self.scheduler.on_tick = self.__tick
        self.scheduler.start()
    
    def stop(self):
        self.scheduler.stop()
        self.scheduler.clear()
    
    def __get_color(self, task: CpuTask):
        if not task.number in self.color_map:
            used_colors = set(self.color_map.values())
            available_colors = [color for color in colors.COLORS if color not in used_colors]
            
            if available_colors:
                color = available_colors[0]
            else:
                color = random_color()
            
            self.color_map[task.number] = color
        return self.color_map[task.number]
    
    def __tick(self, tick: int, task: CpuTask):
        self.cpu.append_task(
            QCpuTaskItem(
                self.__get_color(task),
                'white',
                'P' + str(task.number),
            )
        )
        self.sa_preview.setWidgetResizable(True)
        self.sa_preview.ensureVisible(self.cpu.width(), 0)
        self.cpu.arrow_position = tick
            
    def add_task(self):
        task_priority = self.spn_task_priority.value()
        task_ticks = self.spn_task_ticks.value()

        if task_priority and task_ticks:
            new_task = CpuTask(number=len(self.tasks)+1, priority=task_priority, cost_ticks=task_ticks)
            self.tasks.append(new_task)
            self.update_task_list()
        else:
            QtWidgets.QMessageBox.warning(self, "输入错误", "请填写所有任务信息")

    def save_task(self):
        selected_indexes = self.lst_tasks.selectedIndexes()
        if selected_indexes:
            selected_index = selected_indexes[0].row()
            task_priority = self.spn_task_priority.value()
            task_ticks = self.spn_task_ticks.value()

        if task_priority and task_ticks:
            self.tasks[selected_index].number = selected_index + 1
            self.tasks[selected_index].priority = task_priority
            self.tasks[selected_index].cost_ticks = task_ticks
            self.tasks[selected_index].remaining_ticks = task_ticks
            self.update_task_list()
        else:
            QtWidgets.QMessageBox.warning(self, "输入错误", "请填写所有任务信息")

    def delete_task(self):
        selected_indexes = self.lst_tasks.selectedIndexes()
        if selected_indexes:
            selected_index = selected_indexes[0].row()
            del self.tasks[selected_index]
            # 更新编号
            for i, task in enumerate(self.tasks):
                task.number = i + 1
            self.update_task_list()

    def update_task_list(self):
        model = QtGui.QStandardItemModel()
        for task in self.tasks:
            item = QtGui.QStandardItem(f"[{task.number}] - 优先级: {task.priority} - 时长: {task.cost_ticks}")
            model.appendRow(item)
        self.lst_tasks.setModel(model)


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()